package br.com.fogas.medicao.thread;

import java.sql.SQLException;

import android.util.Log;
import br.com.fogas.database.entidade.NotaFiscal;
import br.com.fogas.database.entidade.NotaOcorrencia;
import br.com.fogas.database.entidade.PlanoVisitas;
import br.com.fogas.database.enums.NotaOcorrenciaStatusEnum;
import br.com.fogas.database.enums.PlanoVisitaStatusEnum;
import br.com.fogas.medicao.R;
import br.com.fogas.medicao.activity.ConcluirSimulNotaActivity;
import br.com.fogas.medicao.application.ApplicationFogas;
import br.com.fogas.medicao.application.Constants;
import br.com.fogas.notafiscal.NotaFiscalEngine;
import br.com.fogas.notafiscal.exception.ClienteBloqueadoSefazException;
import br.com.fogas.notafiscal.exception.NotaNaoAutorizadaException;
import br.com.fogas.notafiscal.exception.NotaNaoEmitidaException;
import br.com.fogas.utils.StringUtility;
import br.com.fogas.webservice.parser.visita.VisitaBody;
import br.com.fogas.webservice.parser.visita.VisitaRequest;
import br.com.fogas.webservice.parser.visita.VisitaRequestItem;
import br.com.fogas.webservice.parser.visita.VisitaResponse;

public class AutorizarNotaOnlineThread extends Thread {

	private ConcluirSimulNotaActivity activity;
	
	private ThreadEventListener listener;
	
	private static final int SEGUNDOS_ESPERA_VERIFICACAO_STATUS_NFE = 10;

	public AutorizarNotaOnlineThread(ConcluirSimulNotaActivity activity, ThreadEventListener listener) {
		this.activity = activity;
		this.listener = listener;
		this.setName("AutorizarNotaThread");
		this.setDaemon(true);
	}
	
	@Override
	public void run() {
		boolean autorizarOnline = ApplicationFogas.getInstance().getConfiguracao().getAppDados().isAutorizar_nfe_online();
		if(autorizarOnline) {
			Log.d(Constants.AUTORIZACAO_NOTA, "iniciando envio on-line");
			enviarNotaOnLine(activity.getNotaImpressao());
		} else {
			Log.d(Constants.AUTORIZACAO_NOTA, "nao habilitado o envio on-line emitir em contigencia!");
			listener.threadComplete(this, new NotaNaoEmitidaException());
		}
	}

	private void enviarNotaOnLine(NotaFiscal notaFiscal) {
		try {
			Log.d(Constants.AUTORIZACAO_NOTA, "enviando a nota para fogas!");
			activity.atualizarStatus(activity.getString(R.string.autor_notaonline_enviando));
			NotaFiscalEngine.enviarNotaFogas(activity.getWebservice(), 
					ApplicationFogas.getInstance().getConfiguracao(), 
					notaFiscal);
			
			activity.atualizarStatus(activity.getString(R.string.autor_notaonline_status));
			
			boolean autorizada = false;
			boolean tempoEsperaEstourado = true;
			int countVerificacoesStatus = 0;
			
			while (activity.getSegundosEsperaAutorizacao() >= 0) {
				if(countVerificacoesStatus == 0) {
					Log.d(Constants.AUTORIZACAO_NOTA, "aguardando 30 segundos verificacao status!");
					Thread.sleep(1000 * 30);
				} else {
					Log.d(Constants.AUTORIZACAO_NOTA, "aguardando "+SEGUNDOS_ESPERA_VERIFICACAO_STATUS_NFE+" segundos verificacao status!");
					Thread.sleep(1000 * SEGUNDOS_ESPERA_VERIFICACAO_STATUS_NFE);
				}
				
				Log.d(Constants.AUTORIZACAO_NOTA, "verificando status da nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum());
				autorizada = NotaFiscalEngine.notaAutorizada(activity.getWebservice(), activity.getDatabase(), notaFiscal);
				
				if(autorizada) {
					tempoEsperaEstourado = false;
					break;
				}
				countVerificacoesStatus++;
			}
			
			if(tempoEsperaEstourado) {
				Log.d(Constants.AUTORIZACAO_NOTA, "tempo espera autorizacao estourado!");
			}
			
			if(autorizada) {
				notaAutorizada(notaFiscal);
			} else {
				notaNaoAutorizada(notaFiscal);
			}
		} catch (ClienteBloqueadoSefazException exception) {
			clienteBloqueadoSefaz(notaFiscal, exception);
		} catch (NotaNaoEmitidaException exception) {
			notaNaoEmitida(notaFiscal, exception);
		}  catch (NotaNaoAutorizadaException exception) {
			notaNaoAutorizada(notaFiscal);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Este metodo atualiza a ultima nota emitida e a nota rejeitada no banco
	 * 
	 * @author andre.nascimento
	 */
	private void clienteBloqueadoSefaz(NotaFiscal notaFiscal, ClienteBloqueadoSefazException exception) {
		//PlanoVisitas planoVisitas = notaFiscal.getTx_plano_visitas();
		Log.d(Constants.AUTORIZACAO_NOTA, "nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum()+
				" nao autorizada cliente "+notaFiscal.getTx_cod_cliente().getTx_cod_cliente()+" - "+notaFiscal.getTx_cod_cliente().getTx_nome()+
				" com restricao na Sefaz!");
		Log.d(Constants.AUTORIZACAO_NOTA, "nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum()+" cancelada!");
		Log.d(Constants.AUTORIZACAO_NOTA, "atualizando ultima nota emitida para serie "+notaFiscal.getTx_serie()+" numero "
		+String.valueOf(Integer.valueOf(notaFiscal.getTx_nfnum()) + 1));
		
		activity.atualizarStatus(activity.getString(R.string.autor_notaonline_restricao_sefaz));
		atualizarUltimaNotaEmitida();
		atualizarNotaEmitida(notaFiscal); 
		listener.threadComplete(this, exception);
	}
	
	/**
	 * Este método finaliza a thread enviando exception de aviso para emitir em contigência pois 
	 * ocorreu algum erro e a nota nem chegou a ser gravada no ECC por isso não precisa atualizar a ultima
	 * nota emitida e nem a nota pois ela continua com nota de simulação e quando for gerada outra 
	 * nota de simulação ela será excluida.
	 * 
	 * @author andre.nascimento
	 */
	private void notaNaoEmitida(NotaFiscal notaFiscal, NotaNaoEmitidaException exception) {
		activity.atualizarStatus(activity.getString(R.string.autor_notaonline_nao_emitida));
		Log.d(Constants.AUTORIZACAO_NOTA, "nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum()+" emitida erro ocorrido!");
		listener.threadComplete(this, exception);
	}

	/**
	 * Este metodo atualiza a ultima nota emitida e a nota autorizada no banco para impress�o
	 * 
	 * @author andre.nascimento
	 */
	private void notaAutorizada(NotaFiscal notaFiscal) {
		Log.d(Constants.AUTORIZACAO_NOTA, "nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum()+" autorizada!");
		Log.d(Constants.AUTORIZACAO_NOTA, "atualizando ultima nota emitida para serie "+notaFiscal.getTx_serie()+" numero "
		+String.valueOf(Integer.valueOf(notaFiscal.getTx_nfnum()) + 1));
		
		activity.atualizarStatus(activity.getString(R.string.autor_notaonline_autorizada));
		atualizarUltimaNotaEmitida();
		atualizarNotaEmitida(notaFiscal);
		finalizarPlanoVisitas(notaFiscal);
		enviarOcorrencia(notaFiscal);
		listener.threadComplete(this, null);
	}
	
	private void enviarOcorrencia(NotaFiscal notaFiscal) {
		try {
			VisitaRequestItem item = new VisitaRequestItem();
			item.setSERIES(StringUtility.leftPad(notaFiscal.getTx_serie(), 3, "0"));
			item.setNFENUM(StringUtility.leftPad(notaFiscal.getTx_nfnum(), 9, "0"));
			item.setOBS1(notaFiscal.getNotaOcorrencia().getTx_obs1());
			item.setOBS2(notaFiscal.getNotaOcorrencia().getTx_obs2());
			item.setPLANO(notaFiscal.getNotaOcorrencia().getTx_plano());
			item.setKUNNR(notaFiscal.getTx_cod_cliente().getTx_cod_cliente());
			item.setURL1(notaFiscal.getNotaOcorrencia().getTx_url1());
			VisitaBody body = new VisitaBody();
			body.setItem(item);
			VisitaRequest request = new VisitaRequest();
			request.setBody(body);
			
			VisitaResponse response = activity.getWebservice().visita(request).getResponse();
			if(response.getItem().getGravado().equals("X")) {
				NotaOcorrencia notaOcorrencia = activity.getDatabase().getNotaOcorrencia().queryForId(notaFiscal.getNotaOcorrencia().getId());
				notaOcorrencia.setNb_sync(NotaOcorrenciaStatusEnum.SINCRONIZADA.getId());
				activity.getDatabase().getNotaOcorrencia().update(notaOcorrencia);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Este metodo atualiza a nota para ser cancelada, status de sincronizacao pendente
	 * para o Job do Sync pegar essa nota e enviar para o ECC para ser cancelada,
	 * e atualiza a ultima nota emitida.
	 * 
	 * @author andre.nascimento
	 */
	private void notaNaoAutorizada(NotaFiscal notaFiscal) {
		Log.d(Constants.AUTORIZACAO_NOTA, "nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum()+" nao autorizada!");
		Log.d(Constants.AUTORIZACAO_NOTA, "nfe serie "+notaFiscal.getTx_serie()+" numero "+notaFiscal.getTx_nfnum()+" cancelada!");
		Log.d(Constants.AUTORIZACAO_NOTA, "atualizando ultima nota emitida para serie "+notaFiscal.getTx_serie()+" numero "
		+String.valueOf(Integer.valueOf(notaFiscal.getTx_nfnum()) + 1));
		
		activity.atualizarStatus(activity.getString(R.string.autor_notaonline_nao_autorizada));
		atualizarUltimaNotaEmitida();
		atualizarNotaEmitida(notaFiscal);
		listener.threadComplete(this, new NotaNaoEmitidaException());
	}
	
	private void atualizarUltimaNotaEmitida() {
		try {
			activity.getDatabase().getNotaControle().atualizarUltimaNotaEmitida();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	private void atualizarNotaEmitida(NotaFiscal notaFiscal) {	
		try {
			activity.getDatabase().getNotaFiscal().update(notaFiscal);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	private void finalizarPlanoVisitas(NotaFiscal notaFiscal) {
		PlanoVisitas planoVisitas = notaFiscal.getTx_plano_visitas();
		planoVisitas.setStatus(PlanoVisitaStatusEnum.FINALIZADO.getId());
		
		Log.d(Constants.AUTORIZACAO_NOTA, "finalizando o plano de visita cliente "+notaFiscal.getTx_cod_cliente().getTx_cod_cliente()+
				" - "+notaFiscal.getTx_cod_cliente().getTx_nome());
		try {
			activity.getDatabase().getPlanoVisitas().update(planoVisitas);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}